<script lang="jsx">
import draggable from 'vuedraggable'
import render from '../../components/render/render'

const components = {
  itemBtns(h, currentItem, index, list) {
    const config = currentItem.__config__
    let card = currentItem.parent
    const { copyItem, deleteItem,moveUpItem,moveDownItem } = this.$listeners
    let showUpBtn = config.showUpBtn
    let showDownBtn = config.showDownBtn
    let upBtnClassName = 'drawing-item-up'
    let downBtnClassName = 'drawing-item-down'
    if (config.tag === 'el-card') {
      if (index === 1) upBtnClassName += ' disabled'
    } else {
      let startDragIndex = 0
      if(card && card.__config__.startDragIndex) startDragIndex = card.__config__.startDragIndex
      if (index === startDragIndex) upBtnClassName += ' disabled'
    }
    if(index === list.length - 1) downBtnClassName += ' disabled'
    return [
      (showUpBtn === false ? null : <span class={upBtnClassName} title="上移" onClick={event => {
         if(!upBtnClassName.includes('disabled')){moveUpItem(index, list)}; event.stopPropagation()
       }}>
         <i class="el-icon-top" />
      </span>)
      ,
      (showDownBtn === false ? null : <span class={downBtnClassName} title="下移" onClick={event => {
        if(!downBtnClassName.includes('disabled')){moveDownItem(index, list)}; event.stopPropagation()
       }}>
         <i class="el-icon-bottom" />
      </span>)
      ,
      (config.showDeleteButton === false ? null : <span class="drawing-item-delete" title="删除" onClick={event => {
        deleteItem(index, list); event.stopPropagation()
      }}>
        <i class="el-icon-delete" />
      </span>)
    ]
  }
}
const layouts = {
  colFormItem(h, currentItem, index, list, option) {
    // console.log('colFormItem.arguments', arguments)
    const { activeItem } = this.$listeners
    const config = currentItem.__config__
    const child = renderChildren.apply(this, arguments)
    let className = 'drawing-item'
    if(this.activeId === config.formId) className += ' active-from-item'
    if(config.visible === false) className += ' hide'
    if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered'
    if (config.canDraggable === false) className += ' undraggable'
    let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null
    if (config.showLabel === false) labelWidth = '0'
    let itemClassItem = config.labelPosition === 'top' ? 'el-form-item--label-top' : ''
    function findParent(el, className) {
      if (el.classList.contains(className)) {
        return el;
      } else {
        return findParent(el.parentNode, className);
      }
    }
    // 解决不可拖动的元素,点击input无法聚焦的问题
    function onPointerdown(e){
      if(!e.target.classList.contains('el-input__inner') && !e.target.classList.contains('el-textarea__inner')) return;
      let f = findParent(e.target, 'drawing-item')
      if(f && f.classList.contains('undraggable')){
        e.target.focus();
        e.preventDefault();
        e.stopPropagation();
      }
    }
    let visible = true
    return visible ? (<el-col span={config.span} class={className}
      nativeOnClick={event => { activeItem(currentItem); event.stopPropagation() }} key={config.renderKey}>
      <el-form-item label-width={labelWidth}
        label={config.showLabel ? config.label : ''} required={config.required} class={itemClassItem}>
        <div onPointerdown={ event=>{
          onPointerdown(event)
        }}>
          <render key={config.renderKey} conf={currentItem} onInput={ event => {
            this.$set(config, 'defaultValue', event)
          }}>
            {child}
          </render>
          {![undefined,null,''].includes(config.tip) && (
            <div class="el-form-item__tip">{config.tip}</div>
          )}
        </div>
      </el-form-item>
      {components.itemBtns.apply(this, arguments)}
    </el-col>) : (<div key={config.renderKey}></div>)
  },
  rowFormItem(h, currentItem, index, list) {
    // console.log('rowFormItem.arguments', arguments)
    const { activeItem } = this.$listeners
    const config = currentItem.__config__
    let className = this.activeId === config.formId
      ? 'drawing-row-item active-from-item'
      : 'drawing-row-item'
    let child = renderChildren.apply(this, arguments)
    if (currentItem.type === 'flex') {
      child = <el-row type={currentItem.type} justify={currentItem.justify} align={currentItem.align} >
              {child}
            </el-row>
    }
    return (
      <el-col span={config.span} key={config.renderKey}>
        <el-row gutter={config.gutter} class={className}
          nativeOnClick={event => { activeItem(currentItem); event.stopPropagation() }}>
          <draggable list={config.children || []} animation={340}
            group="item" class="drag-wrapper">
            {child}
          </draggable>
          {components.itemBtns.apply(this, arguments)}
        </el-row>
      </el-col>
    )
  },
  raw(h, currentItem, index, list) {
    // console.log('raw.arguments', arguments)
    const config = currentItem.__config__
    const child = renderChildren.apply(this, arguments)
    return <render key={config.renderKey} conf={currentItem} onInput={ event => {
      this.$set(config, 'defaultValue', event)
    }}>
      {child}
    </render>
  },
  tsCard(h, currentItem, index, drawingList) {
    const { activeItem } = this.$listeners
    const config = currentItem.__config__
    let className = this.activeId === config.formId
      ? 'drawing-row-item active-from-item'
      : 'drawing-row-item'
    if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered'
    if (config.canDraggable === false) className += ' undraggable'
    const tsCardHeader = []
    const tsCardBody = []
    currentItem.$refs = {}
    config.children.cardHeader.forEach((item, i) => {
      Object.defineProperty(item, 'parent', {
        value: currentItem, enumerable: false
      });
      const layout = layouts[item.__config__.layout]
      tsCardHeader.push(layout.call(this, h, item, i, config.children.cardHeader))
    })
    config.children.cardBody.forEach((item, i) => {
      Object.defineProperty(item, 'parent', {
        value: currentItem, enumerable: false
      });
      const layout = layouts[item.__config__.layout]
      tsCardBody.push(layout.call(this, h, item, i, config.children.cardBody))
    })
    return (
      <el-col span={config.span} class={className}
              nativeOnClick={event => { activeItem(currentItem); event.stopPropagation() }} key={config.renderKey}>
        <el-form-item label-width={config.showLabel ? `${config.labelWidth}px` : '0px'}
                      label={config.showLabel ? config.label : ''} required={config.required}>
          <el-card class="box-card" shadow="never">
            <div slot="header" class="clearfix">
              <div style="display: flex">
                {config.children.cardHeader.length > 0 ? tsCardHeader : <label>{config.label}</label> }
              </div>
            </div>
            <draggable list={config.children.cardBody || []}
                       animation={340} group={config.group} class="drag-wrapper" filter='.undraggable' move={config.checkMove}>
              <transition-group name="flip-list" tag="div">
                {tsCardBody}
              </transition-group>
            </draggable>
          </el-card>
        </el-form-item>
        {components.itemBtns.apply(this, arguments)}
      </el-col>
    )
  }
}

function renderChildren(h, currentItem, index, list) {
  const config = currentItem.__config__
  const children = config.children
  if (!Array.isArray(children)) return null
  return children.map((el, i) => {
    const layout = layouts[el.__config__.layout]
    if (layout) {
      return layout.call(this, h, el, i, children)
    }
    return layoutIsNotFound.call(this)
  })
}

function layoutIsNotFound() {
  throw new Error(`没有与${this.currentItem.__config__.layout}匹配的layout`)
}

export default {
  components: {
    render,
    draggable
  },
  props: [
    'currentItem',
    'index',
    'drawingList',
    'activeId',
    'formConf'
  ],
  render(h) {
    const layout = layouts[this.currentItem.__config__.layout]

    if (layout) {
      return layout.call(this, h, this.currentItem, this.index, this.drawingList)
    }
    return layoutIsNotFound.call(this)
  }
}
</script>
